﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;

/// <summary>
/// Represents any task taken up by individual employee
/// </summary>
public class Task
{
    //!!WARNING : changing name of individual enum members will have impact since the Status is stored in DB by these names
    public enum TaskStatus
    {
        ToDo,
        InProgress,
        Done
    }

    #region Properties
    int _pbi;
    string _description;
    int _empID;
    TaskStatus _status;
    int _priority;
    
    public int PBI
    {
        get
        {
            return _pbi;
        }
        set
        {
            _pbi = value;
        }
    }

    public string Description
    {
        get
        {
            return _description;
        }
        set
        {
            _description = value;
        }
    }

    public int EmpID
    {
        get
        {
            return _empID;
        }
        set
        {
            _empID = value;
        }
    }

    public TaskStatus Status
    {
        get
        {
            return _status;
        }
        set
        {
            _status = value;
        }
    }

    /// <summary>
    /// Highest priority is 1
    /// </summary>
    public int Priority
    {
        get
        {
            return _priority;
        }
        set
        {
            _priority = value;
        }
    }
    #endregion Properties

    private Task()
    { 
    }

    //if object is created outside class(add new task) then have to pass parameters. no status, priority since these will be set to default value.
    public Task(int pbi, string description, int empID)
    {
        this.PBI = pbi;
        this.Description = description;
        this.EmpID = empID;
    }

    public static List<Task> GetAllTasks()
    {
        List<Task> allTasks = new List<Task>();
        DAL dataAccessor = new DAL();
        DataTable dt = dataAccessor.GetAllTasks();
        Task taskObj = null;
        TaskStatus status;
        foreach (DataRow row in dt.AsEnumerable())
        {
            taskObj = new Task();
            taskObj.PBI = Convert.ToInt32(row["PBI"]);
            taskObj.Description = Convert.ToString(row["Description"]);
            taskObj.EmpID = Convert.ToInt32(row["EmpID"]);
            Enum.TryParse(Convert.ToString(row["StatusID"]), out status);
            taskObj.Status = status;
            taskObj.Priority = Convert.ToInt32(row["Priority"]);
            allTasks.Add(taskObj);
        }

        return allTasks;
    }

    public static string GetTaskStatusToDisplay(TaskStatus status)
    {
        switch (status)
        {
            case TaskStatus.ToDo:
                return "To Do";
            case TaskStatus.InProgress:
                return "In Progress";
            case TaskStatus.Done:
                return "Done";
            default:
                return string.Empty;
        }
    }

    public static Dictionary<Task.TaskStatus, string> GetTaskStatusListToDisplay()
    {
        Dictionary<Task.TaskStatus, string> statusList = new Dictionary<Task.TaskStatus, string>();
        for (Task.TaskStatus status = Task.TaskStatus.ToDo; status <= Task.TaskStatus.Done; status++)
        {
            statusList.Add(status, Task.GetTaskStatusToDisplay(status));
        }
        return statusList;
    }

    public bool AddNewTask()
    {
        bool addSuccess;
        //set default status
        this.Status = TaskStatus.ToDo;
        //set default priority
        List<Task> allTasks = Task.GetAllTasks();
        var query = from task in allTasks
                    where task.EmpID == this.EmpID && task.Status == TaskStatus.ToDo
                    select task;
        this.SetDefaultPriority(query);
        DAL dObj = new DAL();
        addSuccess = dObj.InsertTask(this.PBI, this.Description, this.EmpID, this.Status, this.Priority);
        return addSuccess;
    }

    public bool DeleteTask()
    {
        bool delSuccess = false;
        DAL dObj = new DAL();
        delSuccess = dObj.DeleteTask(PBI);
        return delSuccess;
    }

    public bool ArchiveTask()
    {
        bool archiveSuccess = false;
        DAL dObj = new DAL();
        archiveSuccess = dObj.UpdateTask(PBI, EmpID, Status, Priority, true);
        return archiveSuccess;
    }

    public bool MoveTaskToUser(int assignedTo)
    {
        bool moveSuccess = false;        
        List<Task> allTasks = Task.GetAllTasks();
        //select all ToDo tasks for 'assignedTo' employee
        var query = from task in allTasks
                    where task.EmpID == assignedTo && task.Status == TaskStatus.ToDo
                    select task;
        //set priority for this task
        this.SetDefaultPriority(query);
        this.EmpID = assignedTo;
        this.Status = TaskStatus.ToDo;

        DAL dObj = new DAL();
        moveSuccess = dObj.UpdateTask(PBI, EmpID, Status, Priority, false);
        return moveSuccess;
    }

    public bool MoveTaskToStatus(TaskStatus newStatus)
    {
        bool moveSuccess = false;
        //get all tasks for current user for new status        
        List<Task> allTasks = Task.GetAllTasks();
        var query = from task in allTasks
                    where task.EmpID == this.EmpID && task.Status == newStatus
                    select task;
        //set priority, new status for current task and update
        this.SetDefaultPriority(query);
        this.Status = newStatus;

        DAL dObj = new DAL();
        moveSuccess = dObj.UpdateTask(PBI, EmpID, Status, Priority, false);

        return moveSuccess;
    }

    public int IncreasePriority()
    {
        //get all Tasks for current user for current status
        List<Task> allTasks = Task.GetAllTasks();
        var query = from task in allTasks
                    where task.EmpID == this.EmpID && task.Status == this.Status
                    select task;
        int newPriority = 0;
        if (query.Count() > 1)
        {
            //sort the tasks by priority ascending
            List<Task> sortedTasks = query.OrderBy(task => task.Priority).ToList();
            //from sorted list, for task which has same priority as current task swap its priority with higher priority task 
            int rank = 0;
            for (rank = 1; rank < sortedTasks.Count; rank++)
            {
                if (sortedTasks[rank].Priority == this.Priority)
                {
                    newPriority = sortedTasks[rank - 1].Priority;
                    sortedTasks[rank - 1].Priority = this.Priority;
                    this.Priority = newPriority;
                    break;
                }
            }

            if (newPriority != 0)
            {
                //update both tasks //TODO:Transactions
                DAL dObj = new DAL();
                dObj.UpdateTask(PBI, EmpID, Status, Priority, false);
                dObj.UpdateTask(sortedTasks[rank - 1].PBI, sortedTasks[rank - 1].EmpID, sortedTasks[rank - 1].Status, sortedTasks[rank - 1].Priority, false);
            }
        }
        return newPriority;
    }

    public int DecreasePriority()
    {
        //get all Tasks for current user for current status
        List<Task> allTasks = Task.GetAllTasks();
        var query = from task in allTasks
                    where task.EmpID == this.EmpID && task.Status == this.Status
                    select task;
        int newPriority = 0;
        if (query.Count() > 1)
        {
            //sort the tasks by priority ascending
            List<Task> sortedTasks = query.OrderBy(task => task.Priority).ToList();
            //from sorted list, for task which has same priority as current task swap its priority with lower priority task
            int rank = 0;
            for (rank = sortedTasks.Count() - 2; rank >= 0; rank--)
            {
                if (sortedTasks[rank].Priority == this.Priority)
                {
                    newPriority = sortedTasks[rank + 1].Priority;
                    sortedTasks[rank + 1].Priority = this.Priority;
                    this.Priority = newPriority;
                    break;
                }
            }
            if (newPriority != 0)
            {
                //update both tasks //TODO:Transactions
                DAL dObj = new DAL();
                dObj.UpdateTask(PBI, EmpID, Status, Priority, false);
                dObj.UpdateTask(sortedTasks[rank + 1].PBI, sortedTasks[rank + 1].EmpID, sortedTasks[rank + 1].Status, sortedTasks[rank + 1].Priority, false);
            }
        }
        return newPriority;
    }

    void SetDefaultPriority(IEnumerable<Task> query)
    {
        if (query.Count() > 0)
        {
            this.Priority = query.Max(task => task.Priority) + 1;
        }
        else
        {
            this.Priority = 1;
        }
    }

    /// <summary>
    /// Returns number of tasks of an employee for a given status
    /// </summary>
    /// <param name="allTasks"></param>
    /// <param name="empID"></param>
    /// <param name="status"></param>
    /// <returns></returns>
    public static int GetTaskCount(List<Task> allTasks, int empID, Task.TaskStatus status)
    {
        int taskCount = allTasks.Where(task => task.EmpID == empID && task.Status == status).Count();
        return taskCount;
    }
}